local nbt = require("nbt")

local function byte2hexImpl(a)
	return string.format("%02x", a:byte())
end

local function byte2hex(a)
	return a:gsub(".", byte2hexImpl)
end

describe("NBT", function()
	describe("Tag class", function()
		it("should truncate floating value for getInteger()", function()
			local x = nbt.newDouble(6624.20166)
			assert.is.equal(6624, x:getInteger())
		end)

		it("should try to convert input to number for new integer/float type", function()
			assert.is_not.error(function()
				assert.is.equal(nbt.newInt("0x7fffffff"):getInteger(), nbt.newInt("2147483647"):getInteger())
				nbt.newFloat("6624.21066")
				nbt.newDouble("6624.20166")
			end)
			assert.is.error(function()
				nbt.newInt("invalid number")
			end)
		end)

		it("should tostring() input first for nbt.newString", function()
			assert.is.equal("123456", nbt.newString(123456):getString())
		end)

		describe(":getNumber/Integer()", function()
			it("should try to convert string to number", function()
				assert.is_not.error(function()
					local x = nbt.newString("6624.20166")
					assert.is.equal(6624, x:getInteger())
					assert.is.equal(6624.20166, x:getNumber())
				end)
			end)

			it("should error if string to number conversion fails", function()
				assert.is.error(function()
					nbt.newString(io):getNumber()
				end)
			end)
		end)

		describe(":getString()", function()
			it("should work for integer/number tags", function()
				assert.is.equal("6624.20166", nbt.newDouble(6624.20166):getString())
				assert.is.equal("2147483647", nbt.newInt("0x7fffffff"):getString())
			end)

			it("should error for array & compound types", function()
				local x
				assert.is.error(function()
					nbt.newList(nbt.TAG_SHORT, {1, 2, 3, 4, 5}):getString()
				end)
				assert.is.error(function()
					nbt.newIntArray({1, 2, 3, 4}):getString()
				end)
				assert.is.error(function()
					nbt.newLongArray({1, 2, 3, 4}):getString()
				end)
				assert.is_not.error(function()
					x = nbt.newCompound({
						key = nbt.newString("hello"),
						test = nbt.newString("123 OK")
					})
				end)
				assert.is.error(function() x:getString() end)
			end)
		end)
	end)
	describe("encoding", function()
		it("should encode integers/floats in big endian order", function()
			assert.is.equal("7fff", byte2hex(nbt.newShort(32767):encode(true)))
			assert.is.equal("NPad", nbt.newInt(1313890660):encode(true))
			assert.is.equal("bf800000", byte2hex(nbt.newFloat(-1):encode(true)))
			assert.is.equal("c030000000000000", byte2hex(nbt.newDouble(-16):encode(true)))
		end)

		it("should encode null byte in string as 0xc0 and 0x80", function()
			assert.is.equal("0004c080c080", byte2hex(nbt.newString("\0\0"):encode(true)))
		end)
	end)
end)